//
//  DGAccountStore.m
//  DGAccountKit
//
//  Created by Jinxiao on 11/19/13.
//  Copyright (c) 2013 debugeek. All rights reserved.
//

#import "DGAccountStore.h"
#import "DGAccount.h"
#import "DGAccountError.h"

NSString * const DGAccountWillRemoveNotification = @"DGAccountWillRemoveNotification";
NSString * const DGAccountDidRemoveNotification = @"DGAccountDidRemoveNotification";
NSString * const DGAccountWillSaveNotification = @"DGAccountWillSaveNotification";
NSString * const DGAccountDidSaveNotification = @"DGAccountDidSaveNotification";
NSString * const DGAccountWillUpdateNotification = @"DGAccountWillUpdateNotification";
NSString * const DGAccountDidUpdateNotification = @"DGAccountDidUpdateNotification";
NSString * const DGCurrentAccountWillChangeNotification = @"DGCurrentAccountWillChangeNotification";
NSString * const DGCurrentAccountDidChangeNotification = @"DGCurrentAccountDidChangeNotification";
NSString * const DGAccountProfileWillUpdateNotification = @"DGAccountProfileWillUpdateNotification";
NSString * const DGAccountProfileDidUpdateNotification = @"DGAccountProfileDidUpdateNotification";
NSString * const DGAccountOldAccountKey = @"DGAccountOldAccountKey";
NSString * const DGAccountNewAccountKey = @"DGAccountNewAccountKey";
NSString * const DGAccountKey = @"DGAccountKey";
NSString * const DGAccountErrorKey = @"DGAccountErrorKey";

NSMutableArray *AccountItemsFromUserDefaults()
{
    NSMutableArray *items = [[[NSUserDefaults standardUserDefaults] arrayForKey:@"DGAccounts"] mutableCopy];
    if(!items)
    {
        items = [NSMutableArray array];
    }
    
    return items;
}

NSDictionary *AccountItemForIdentifier(NSString *identifier)
{
    NSArray *accountItems = AccountItemsFromUserDefaults();
    for(NSDictionary *accountItem in accountItems)
    {
        if([[accountItem objectForKey:DGAccountKeyIdentifier] isEqualToString:identifier])
        {
            return accountItem;
        }
    }
    
    return nil;
}

void DGAccountSaveAccountsToStore(NSArray *accounts)
{
    [[NSUserDefaults standardUserDefaults] setObject:accounts forKey:@"DGAccounts"];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

@interface DGAccountStore ()
{
    NSMutableArray *_accounts;
}
@property (nonatomic, readwrite, strong) NSMutableArray *accounts;
@end

@implementation DGAccountStore

+ (instancetype)sharedInstance
{
    static id instance;
    static dispatch_once_t once;
    dispatch_once(&once, ^{
        instance = self.new;
    });
    return instance;
}

- (void)loadAccountsFromLocal
{
    if(_accounts == nil)
    {
        self.accounts = [NSMutableArray array];
    }
    else
    {
        [_accounts removeAllObjects];
    }
    
    NSArray *accountItems = AccountItemsFromUserDefaults();
    
    for(NSDictionary *accountItem in accountItems)
    {
        DGAccount *account = [[DGAccount alloc] init];
        [account updateWithDictionary:accountItem];
        [_accounts addObject:account];
    }
}

- (DGAccount *)accountByIdentifier:(NSString *)identifier
{
    if(!identifier)
    {
        return nil;
    }
    
    for(DGAccount *account in _accounts)
    {
        if([account.identifier isEqualToString:identifier])
        {
            return account;
        }
    }
    
    return nil;
}

- (BOOL)checkDuplicateAccount:(DGAccount *)anAccount
{
    if(anAccount.userID == nil)
    {
        return NO;
    }
    
    for(DGAccount *account in _accounts)
    {
        if([account.userID isEqualToString:anAccount.userID])
        {
            return NO;
        }
    }
    
    return YES;
}

- (BOOL)canSaveAccount:(DGAccount *)account error:(NSError **)error
{
    if([account validateAccount])
    {
        if([self checkDuplicateAccount:account])
        {
            return YES;
        }
        else
        {
            if(error)
            {
                *error = [NSError errorWithDomain:DGAccountErrorDomain code:DGAccountErrorAccountAlreadyExists userInfo:nil];
            }
            
            return NO;
        }
    }
    else
    {
        if(error)
        {
            *error = [NSError errorWithDomain:DGAccountErrorDomain code:DGAccountErrorMissingRequiredProperty userInfo:nil];
        }
        
        return NO;
    }
}

- (void)saveAccount:(DGAccount *)account options:(DGAccountStoreUpdateOptions)options completion:(DGAccountStoreOperationCompletion)completion
{
    NSError *error = nil;
    if([self canSaveAccount:account error:&error])
    {
        NSDictionary *userInfo = @{DGAccountNewAccountKey : account};
        [[NSNotificationCenter defaultCenter] postNotificationName:DGAccountWillSaveNotification object:self userInfo:userInfo];
        
        NSMutableArray *accountItems = AccountItemsFromUserDefaults();
        [accountItems addObject:[account dictionaryRepresentation]];
        DGAccountSaveAccountsToStore(accountItems);
        
        [account.credential saveCredentials];
        [account.credential loadCredentials];
        
        [_accounts addObject:account];
        
        if(completion)
        {
            completion(YES, nil);
        }
        
        [[NSNotificationCenter defaultCenter] postNotificationName:DGAccountDidSaveNotification object:self userInfo:userInfo];
    }
    else if(completion)
    {
        completion(NO, error);
    }
}

- (void)updateAccount:(DGAccount *)account options:(DGAccountStoreUpdateOptions)options completion:(DGAccountStoreOperationCompletion)completion
{
    NSDictionary *oldAccountItem = AccountItemForIdentifier(account.identifier);
    if(oldAccountItem)
    {
        NSDictionary *userInfo = @{DGAccountKey : account};
        [[NSNotificationCenter defaultCenter] postNotificationName:DGAccountWillUpdateNotification object:self userInfo:userInfo];
        
        NSMutableArray *accountItems = AccountItemsFromUserDefaults();
        NSDictionary *newAccountItem = [account dictionaryRepresentation];
        [accountItems replaceObjectAtIndex:[accountItems indexOfObject:oldAccountItem] withObject:newAccountItem];
        DGAccountSaveAccountsToStore(accountItems);
        
        if(options&DGAccountStoreUpdateAccountCredential)
        {
            [account.credential saveCredentials];
            [account.credential loadCredentials];
        }
        
        if(completion)
        {
            completion(YES, nil);
        }
        
        [[NSNotificationCenter defaultCenter] postNotificationName:DGAccountDidUpdateNotification object:self userInfo:userInfo];
    }
    else if(completion)
    {
        completion(YES, [NSError errorWithDomain:DGAccountErrorDomain code:DGAccountErrorAccountNotFound userInfo:nil]);
    }
}

- (void)removeAccount:(DGAccount *)account options:(DGAccountStoreUpdateOptions)options completion:(DGAccountStoreOperationCompletion)completion
{
    if(!account)
    {
        return;
    }
    
    NSDictionary *accountItem = AccountItemForIdentifier(account.identifier);
    if(accountItem)
    {
        NSDictionary *userInfo = @{DGAccountOldAccountKey : account};
        [[NSNotificationCenter defaultCenter] postNotificationName:DGAccountWillRemoveNotification object:self userInfo:userInfo];
        
        NSMutableArray *accountItems = AccountItemsFromUserDefaults();
        [accountItems removeObject:accountItem];
        DGAccountSaveAccountsToStore(accountItems);
        
        [_accounts removeObject:account];
        
        if(completion)
        {
            completion(YES, nil);
        }
        
        [[NSNotificationCenter defaultCenter] postNotificationName:DGAccountDidRemoveNotification object:self userInfo:userInfo];
    }
    else if(completion)
    {
        completion(YES, [NSError errorWithDomain:DGAccountErrorDomain code:DGAccountErrorAccountNotFound userInfo:nil]);
    }
}

@end